Report: GraphQL Schema Design @ Scale
概要
GraphQL Summit 2018 における GitHub の Marc 氏の発表。
https://youtu.be/pJamhW2xPYw
中略。利用ツールについて知りたくなったので現状そこだけまとめている。
GitHub で利用しているツール
Checked-in SDL
GitHub では、GraphQL ruby gem を利用して Ruby クラスで GraphQL スキーマを記述しており、SDL は直接記述していない。そのため、開発者が GraphqL スキーマに変更をいれたら、スキーマの SDL をダンプし、GitHub リポジトリに追加する。
code:shell
$ bin/dump-graphql-schema
config/schema.public.graphql
$ git add config/schema.public.graphql
SDL のダンプは、内部向け、外部向け、Enterprise 向けが各々行える。SDL を GitHub にあげ、SDL の PR をなげる。Ruby コードを直接読むよりも、こちらの方がはるかにわかりやすい。
GraphQL Schema Comparator
変更されたスキーマに対して schema comparator を走らせる。GitHub のクライアントは種類も数もとても多いので、破壊的な変更があれば CI を落とす。 また、日々の GraphQL の Change Log を出力するのにも利用している。この Change Log は一般に 公開されている GraphQL Doctor
しかし、schema comparator でいちいちテストが落とされるとイライラしてしまう。指摘されたら必ずコード修正をする必要があるし、そのために変更の反映が遅れてしまう。そのため、GraphQL Doctor を導入した。GraphQL Doctor は PR のレビュー bot で、GraphQL 変更時のベストプラクティスを指摘してくれる。
GraphQL Docs
セッション内で紹介したような内部的な GraphQL API 設計の Tips を、社内のプライベートリポジトリにまとめている。さらに、そこに記述したルールを GraphQL Doctor が読み込んで指摘してくれる。
スキーマの一部を Deprecated にする
スキーマ設計は難しく、ミスもある。そのような時にはDirectives として @deprecated が利用できる。@deprecated は reason が指定できるが、利用者にとってはそこに一貫性があることがのぞましい。 code:graphql
type ExampleType {
newField: String
oldField: String @deprecated(reason: "Use newField.")
}
そこで、Ruby の API として、3つの項目の記述を強制している。SDL に変換するさにはこれがエンコードされ、文字列となる。
code:ruby
deprecated(
start_date: Date.new(2018, 1, 15),
reason: "We do not use databaseID anymore.",
superseded_by: "Use Node.id instead."
)
code:graphql
type Repository {
databaseId: ID! @deprecated(reason: "databaseID will be removed. USe Node.id instead. Removal on 2017-07-01 UTC.")
}
code:graphql
type Repository {
issues(
# Deprecated: states will be removed. Use newStates instead. Removal on 2018-07-01 UTC.")
}
上記メタ情報から、Breaking Changes のページを自動生成している。このページは人の手は全く加えられておらず、全て Ruby スキーマから収集したメタ情報から自動生成されている。 Deprecated にしたスキーマを変更する
Deprecated なスキーマを周知することは簡単だが、実際に変更を加える際には注意が必要となる。というのも、削除しようとしているフィールドの利用者がわからないためである。しかし、GraphQL の良いところは "No Select *"、すなわちクライアントは全てのフィールドを取得するのではなく、必要なフィールドのみを取得しているので、個々のフィールド、引数、enum 毎にそれが利用されているか?を分析できる。
GitHub API がヒットした場合、それを GraphQL Query Analytics サービスのキューに積む。Analytics サービスは受け取ったクエリの情報を Type, Field, 利用している App 等のデータに分解する。そして、それらを全てデータとして格納する。
code:diagram
query { +--------+ +---------------+ | Type:Query |
viewer { | | | | | Field: viewer |
login ---> | GitHub | ---> | GraphQL Query | ---> | App: xxx | ---> DataWarehouse
email | API | | Analytics | | |
} | | | | | Type: User |
} +--------+ +---------------+ | Field: login |
| App: xxx |
| |
| ... |
まとめ
Talk to, (or become) domain experts
関わっているビジネスやそのアプリケーションについて考える
Think Domain over Data
ドメインの裏にデータがどのように存在しているのか?どのデータがエンティティに利用されているのか?それらは何ができて、どのような振る舞いをみせるのか?
Sometimes it's not about "One Size Fits All"
全てを賄える 1 つのフィールドを提供する代わりに、ユースケースに合わせてそれを分割したり、異なる方法で提供したりした方が良いこともある。
Use the schema to build (or use) great tools!
型システムやメタデータの恩恵があるので、エンジニアのワークフローやクライアントの開発を支援する素晴らしいツールの開発が行える。